package com.voice.server.config;

import com.voice.core.DefaultClient;
import com.voice.core.channel.IOContext;
import com.voice.core.channel.tcp.impl.IOSelectorContext;
import com.voice.core.utils.ThreadFactoryUtil;
import com.voice.server.connection.ConnectionInvoke;
import com.voice.server.properties.*;
import com.wangjiacai.hqlQuery.repository.BaseRepository;
import com.wangjiacai.hqlQuery.repository.impl.EntityManagerBaseRepositoryImpl;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.persistence.EntityManager;
import java.io.IOException;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicInteger;

@Configuration
@EnableConfigurationProperties({ ThreadPoolProperties.class,FilterProperties.class,ServerProperties.class})
public class BeanConfig {

    @Bean
    @Primary
    public Executor executorService(ThreadPoolProperties threadPoolProperties){
        final AtomicInteger threadNumber = new AtomicInteger(1);
        return Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()*threadPoolProperties.getPoolSize(),(runnable)->{
            Thread thread=new Thread(runnable,"voice-pool"+"-thread-"+threadNumber.getAndIncrement());
            thread.setDaemon(true);
            return thread;
        });
    }

    @Bean
    public ScheduledThreadPoolExecutor scheduledThreadPoolExecutor(ThreadPoolProperties threadPoolProperties){
        final AtomicInteger threadNumber = new AtomicInteger(1);
        ScheduledThreadPoolExecutor scheduledThreadPoolExecutor=new ScheduledThreadPoolExecutor(threadPoolProperties.getSchedulePoolSize(),(runnable)->{
            Thread thread=new Thread(runnable,"schedule-pool"+"-thread-"+threadNumber.getAndIncrement());
            thread.setDaemon(true);
            return thread;
        });
        return scheduledThreadPoolExecutor;
    }

    @Bean("inputPool")
    public ExecutorService inputPool(ThreadPoolProperties threadPoolProperties){
        return Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()*threadPoolProperties.getInputPool(), ThreadFactoryUtil.threadFactory("IOSelectorContext inputPool"));
    }

    @Bean("outputPool")
    public ExecutorService outputPool(ThreadPoolProperties threadPoolProperties){
        return Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()*threadPoolProperties.getOutputPool(), ThreadFactoryUtil.threadFactory("IOSelectorContext outPool"));
    }

    @Bean
    public ConnectionInvoke connectionInvoke(ExecutorService inputPool, ExecutorService outputPool) throws IOException {
        IOContext ioContext=new IOSelectorContext(inputPool,outputPool);
        return new ConnectionInvoke(ioContext);
    }

    @Bean
    public DefaultClient defaultClient(){
        return new DefaultClient();
    }

    @Bean
    public RestTemplate restTemplate() throws Exception {
        TrustStrategy acceptingTrustStrategy=(X509Certificate[] chain, String authType)-> true;
        SSLContext sslContext= SSLContexts.custom().loadTrustMaterial(KeyStore.getInstance(KeyStore.getDefaultType()),acceptingTrustStrategy).build();

        HostnameVerifier verifier = (String hostname, SSLSession session)-> true;
        SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, verifier);
        CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(csf).build();

        HttpComponentsClientHttpRequestFactory requestFactory =new HttpComponentsClientHttpRequestFactory();
        requestFactory.setHttpClient(httpClient);
        return new RestTemplate(requestFactory);
    }

}
